import sys
import os
import subprocess
import re
from PyQt4.QtGui import *
from PyQt4.QtCore import *





class AssemblyHighlighter( QSyntaxHighlighter ):

    def __init__( self, parent):
        QSyntaxHighlighter.__init__( self, parent )
        self.parent = parent
        self.highlightingRules = []
        


        #============= add keywords to syntax =========================================

        keywordFormat = QTextCharFormat()
        keywordFormat.setForeground( Qt.darkBlue )
        keywordFormat.setFontWeight( QFont.Bold )
        keywords = QStringList( [ "ORG", "END", "MOV", "CLR", "SETB",
                                  "MOVX", "CPL", "POP", "PUSH","BIT"
                                  "NOP", "RET","RETI","INC","DEC","RR","RL",
                                  "ORL","ANL","ADD","RLC","ADDC","XRL","EQU","CODE","DATA","IDATA","XDATA",
                                  "BIT","SUBB","MUL","XCH","RRC","SWAP","XCHD","DB","DW","DS","DBIT","AT",

                                  ] )

        self.highlightingRules = [(QRegExp("\\b" + pattern + "\\b"), keywordFormat)
                for pattern in keywords]


        for word in keywords:
            patternU = QRegExp("\\b" + word + "\\b")
            patternL = QRegExp("\\b" + word.toLower()+"\\b")
            self.highlightingRules.append((patternU,keywordFormat))
            self.highlightingRules.append((patternL,keywordFormat))
                

        ##======== add special function registers and bits ===========================

        specialFunctionRegisters = QTextCharFormat()
        specialFunctionRegisters.setForeground( Qt.darkRed )
        specialFunctionRegisters.setFontWeight( QFont.Bold )
        keywords = QStringList( [ "P0", "P1", "P2","AC","CY","OV","P",
                                  "F0","RS1","RS0","CSEG","DSEG","ISEG",
                          "P3", "ACC","PSW","PCH","PCL","BSEG","XSEG",
                          "B", "C","PCON","TCON","SCON","SBUF","IE","IP",
                          "SP", "DPL", "DPH","TMOD","TL0","TL1","TH0","TH1",
                          "DPTR" ] )

        for word in keywords:
            
            patternU = QRegExp("\\b" + word + "\\b")
            patternL = QRegExp("\\b" + word.toLower()+"\\b")
            self.highlightingRules.append((patternU,specialFunctionRegisters))
            self.highlightingRules.append((patternL,specialFunctionRegisters))

        self.highlightingRules.append((QRegExp("\\b[aA|bB]\\b"),specialFunctionRegisters))
       #=============================================================================     

        #add jumping instructions to syntax .........................................

        jumpingFormat = QTextCharFormat()
        jumpingFormat.setForeground(QColor(255,2,255))  #magenta


        keywords = QStringList( ["JMP","SJMP","AJMP","LJMP","ACALL","DJNZ","JB",
                                  "JNB","JC","JNC","JNZ","JZ",
                                  "LCALL","JBC","CJNE",])


        for word in keywords:
            
            patternU = QRegExp("\\b" + word + "\\b")
            patternL = QRegExp("\\b" + word.toLower()+"\\b")
            self.highlightingRules.append((patternU,jumpingFormat))
            self.highlightingRules.append((patternL,jumpingFormat))


        #============================================================================    


     
        #match labels
        pattern = QRegExp( "^[a-zA-Z0-9_]+:" )
        labelIndicator = QTextCharFormat()
        labelIndicator.setForeground(Qt.green)
        labelIndicator.setFontWeight(QFont.Bold)
        self.highlightingRules.append((pattern,labelIndicator))

        pattern = QRegExp("R[0-7]|r[0-7]")
        registerFormat = QTextCharFormat()
        registerFormat.setForeground(Qt.darkCyan)
        registerFormat.setFontWeight(QFont.Bold)
        self.highlightingRules.append((pattern,registerFormat))
        

        #match ascii characters or strings 
        pattern = QRegExp("'[a-z|A-Z|0-9]'|\"[a-zA-Z0-9]*\"")
        charFormat = QTextCharFormat()
        charFormat.setForeground(QColor(124,252,0))     #lawn green
        self.highlightingRules.append((pattern,charFormat))

        #match R0-R7 registers with @ symbol 
        pattern = QRegExp("@R[0-7]|@r[0-7]")
        charFormat = QTextCharFormat()
        charFormat.setForeground(QColor(165,42,42))  #brown
        self.highlightingRules.append((pattern,charFormat))


        #match for imidiate numbers

        pattern = QRegExp("(#[0-9a-fA-F]{1,4}[H|h])|(#[0-1]{1,8}[b|B])|(#[0-9]*D\\b)")
        charFormat = QTextCharFormat()
        charFormat.setForeground(QColor(0,139,139))  #dark cyan 
        self.highlightingRules.append((pattern,charFormat))


        #match address numbers
        pattern = QRegExp("(\\,[0-9a-fA-F]{1,4}[H|h])|(\\,[0-1]{1,8}[b|B])|(\\,[0-9]*D\\b)")
        charFormat = QTextCharFormat()
        charFormat.setForeground(QColor(184,134,11))  #dark golden
        self.highlightingRules.append((pattern,charFormat))


        #match bit addressable
        pattern = QRegExp("[a-zA-Z0-9]*\\.[0-7]\\b")
        charFormat = QTextCharFormat()
        charFormat.setForeground(QColor(138,43,226))  #blue violet
        self.highlightingRules.append((pattern,charFormat))
        


        #single line comenting 
        singleLineCommentFormat = QTextCharFormat()
        singleLineCommentFormat.setForeground(Qt.red)
        singleLineCommentFormat.setBackground(QColor(240,255,240))
        singleLineCommentFormat.setFontPointSize(10)
        self.highlightingRules.append((QRegExp(";[^\n]*"),
                singleLineCommentFormat))

        #=================================================================================
        

        #self.commentStartExpression =QRegExp("/\\*")
        #self.commentEndExpression = QRegExp("\\*/")


      

        #self.multiLineCommentFormat = QTextCharFormat()
        #self.multiLineCommentFormat.setForeground(Qt.red)




        
#=====================do highlighting of the text===========================================

    def highlightBlock(self, text):
        for pattern, format in self.highlightingRules:
            expression = QRegExp(pattern)
            index = expression.indexIn(text)
            while index >= 0:
                length = expression.matchedLength()
                self.setFormat(index, length, format)
                index = expression.indexIn(text, index + length)

        self.setCurrentBlockState(0)

       # startIndex = 0
       # if self.previousBlockState() != 1:
       #     startIndex = self.commentStartExpression.indexIn(text)

       # while startIndex >= 0:
       #     endIndex = self.commentEndExpression.indexIn(text, startIndex)

       #     if endIndex == -1:
       #         self.setCurrentBlockState(1)
       #         commentLength = len(text) - startIndex
       #     else:
       #        commentLength = endIndex - startIndex + self.commentEndExpression.matchedLength()

       #     self.setFormat(startIndex, commentLength,
       #             self.multiLineCommentFormat)
       #     startIndex = self.commentStartExpression.indexIn(text,
       #             startIndex + commentLength);
#========================================================================================        



#from LNTextEdit import *

class MainWindow( QMainWindow ):
    def __init__(self):
        QMainWindow.__init__(self)

        
        self.curFileName=None
        self.appName = "pyKasm51 V_1.0 "
        self.resultList = QListWidget(self)
        self.resultList.itemClicked.connect(self.item_click)

        self.setWindowIcon(QIcon("icons/mainIcon.ico"))
        self.setWindowTitle( self.appName )

        

        #create a text editor
        self.editor = QTextEdit()
        self.editor.setLineWrapMode(QTextEdit.NoWrap);
        self.isError = False;
        self.editor.cursorPositionChanged.connect(self.moveLineCursor)
        

        #configure editor's background color
        p = self.editor.palette();
        p.setColor(QPalette.Base, QColor(252,250,255)) #ivory
        self.editor.setPalette(p)

        
        #set editor's font
        font = QFont()
        font.setFamily('Consolas')  
        font.setFixedPitch(True)
        font.setPointSize(14)
        self.editor.setFont(font)

        #create syntax highlighter from above text editor
        highlighter = AssemblyHighlighter( self.editor )
        
        self.createMenuActions()
        self.createStandardToolbar()

        

        #prepare layout of the main window

        v_splitter =QSplitter(Qt.Vertical,self)
        v_splitter.addWidget(self.editor)
        v_splitter.addWidget(self.resultList)
        v_splitter.setSizes([600,150]) 


        #set centeral widget of the main class and respective title
        self.setCentralWidget( v_splitter )
        


    def moveLineCursor(self):
        if not self.isError:
            extraSelections=[]
            lineColor = QColor(Qt.yellow).lighter(190)
            selection=QTextEdit.ExtraSelection()
            selection.format.setBackground(lineColor)
            selection.format.setProperty(QTextFormat.FullWidthSelection, True)

            cursor = self.editor.textCursor();
            selection.cursor = cursor
            selection.cursor.clearSelection()
            extraSelections.append(selection)
            self.editor.setExtraSelections(extraSelections)
            
        

    def item_click(self,item):
        #print  str(item.text())
        curL = str(item.text())
        m=re.search('\([0-9]+\)',curL)
        if m:
              
            lineNText = m.group(0)
            lineNText = filter(str.isdigit,lineNText)
            
            extraSelections=[]
            lineColor = QColor(Qt.red).lighter(160)
            selection=QTextEdit.ExtraSelection()
            selection.format.setBackground(lineColor)
            selection.format.setProperty(QTextFormat.FullWidthSelection, True)

            cursor = self.editor.textCursor();
            #cursor.movePosition(int(lineText));
            #self.editor.setTextCursor(cursor);     

            #self.editor.moveCursor(QTextCursor.Left, QTextCursor.MoveAnchor, int(lineText))

            #selection.cursor = self.editor.textCursor()
           
          
            print lineNText

            plaintxt = self.editor.toPlainText();
            linetxt = plaintxt.split('\n')
            plaintxt =map(str, plaintxt)

            
            linetxt = map(str,linetxt)

            lineN = int(lineNText)-1

            print linetxt[lineN].strip()
            print len(''.join(linetxt[0:lineN]))

            
        


            selection.cursor = cursor
            blockN= selection.cursor.blockNumber()

            linedif = lineN - blockN
            if linedif<0:
                selection.cursor.movePosition(QTextCursor.PreviousBlock,QTextCursor.MoveAnchor, -linedif)
            else:
                selection.cursor.movePosition(QTextCursor.NextBlock,QTextCursor.MoveAnchor, linedif)

            
            #selection.cursor.movePosition(QTextCursor.PreviousBlock,QTextCursor.MoveAnchor, lineN)
            selection.cursor.clearSelection()
            extraSelections.append(selection)
            self.editor.setExtraSelections(extraSelections)
            
            
           
            

            
            
        


    #============= creating file Menu Actions ==================================
    
    def createMenuActions(self):
        self.file_NewAction =QAction(QIcon('icons/file_new.ico'),'New',self)
        self.file_NewAction.setShortcut('Ctrl+N')
        self.file_NewAction.triggered.connect(self.newFile)

        self.file_OpenAction =QAction(QIcon('icons/file_open.ico'),'Open',self)
        self.file_OpenAction.setShortcut('Ctrl+O')
        self.file_OpenAction.triggered.connect(self.openFile)


        self.file_saveAction =QAction(QIcon('icons/file_save.ico'),'Save',self)
        self.file_saveAction.setShortcut('Ctrl+S')
        self.file_saveAction.triggered.connect(self.saveFile)
        

        self.compileAction = QAction(QIcon('icons/compile.ico'), 'Compile',self)
        self.compileAction.setShortcut('F2')
        self.compileAction.triggered.connect(self.compileEvent)
        
    
        self.exitAction =QAction(QIcon('icons/exit.ico'), 'Exit', self)
        self.exitAction.setShortcut('Ctrl+Q')
        self.exitAction.triggered.connect(self.close)

    #===========================================================================
    def compileEvent(self):
        self.saveFile()
        self.resultList.clear()
        
        try:
            if not self.curFileName:
                             
                QMessageBox.about(self,"Error","Please Save your file first")
            else:
                cmd = "bin\\asemw.exe \""+os.path.abspath(self.curFileName)+"\""
                #print cmd
                resp= os.popen(cmd).read()
                lines= resp.split('\n')
                #------------------------------------------
                if resp.find("detected")>-1:
                    #print 'there are some errors in code'
                    pass



                #------------------------------------------          
                for t1 in lines:
                    
                    self.resultList.addItem(t1)
                    #print t1
        except:
            QMessageBox.about(self,"Error","Error in compiling")


    #===================================================================            

    def newFile(self):
        self.editor.clear()
        self.curFileName = None
        self.setWindowTitle( self.appName+" (New*)" )
        self.resultList.clear()

    #===================================================================
    def openFile(self, path=None):
        if not self.curFileName:
            path = QFileDialog.getOpenFileName(self, "Open File",
                    '', "ASM Files (*.asm *.a51)")
        else:
            path = QFileDialog.getOpenFileName(self, "Open File",
                    self.curFileName, "ASM Files (*.asm *.a51)")
            
        if path:
            inFile = QFile(path)
            if inFile.open(QFile.ReadOnly | QFile.Text):
                text = inFile.readAll()

                try:
                    # Python v3.
                    text = str(text, encoding='ascii')
                except TypeError:
                    # Python v2.
                    text = str(text)

                self.editor.setPlainText(text)
                self.curFileName=path
                self.setWindowTitle( self.appName +" (" +self.curFileName+" )")
                


    #===================================================================================================

    def saveFile(self):
        #QMessageBox.about(self,"text",self.editor.toPlainText())

        if not self.curFileName:
            filename = QFileDialog.getSaveFileName(self, 'Save File', '',"ASM Files (*.asm *.a51)")
            if filename:
                self.curFileName=filename
                try:
                     f = open(self.curFileName, 'w')
                     filedata = self.editor.toPlainText()
                     f.write(filedata)
                     f.close()
                     self.setWindowTitle( self.appName +" (" +self.curFileName+" )")
                except:
                    QMessageBox.Ok(self,"Erro","Error occured while saving file")

        else:
             try:
                 f = open(self.curFileName, 'w')
                 filedata = self.editor.toPlainText()
                 f.write(filedata)
                 f.close()
                 self.setWindowTitle( self.appName +" (" +self.curFileName+" )")
                 
             except:
                 QMessageBox.about(self,"Erro","Error occured while saving file")

            
                    

      #=========================================================================================== 

       
        


    def createStandardToolbar(self):
        self.toolbar = self.addToolBar('Main Tool Bar')
        self.toolbar.addAction(self.file_NewAction)
        self.toolbar.addAction(self.file_OpenAction)
        self.toolbar.addAction(self.file_saveAction)
        self.toolbar.addSeparator()
        self.toolbar.addAction(self.compileAction)
        self.toolbar.addAction(self.exitAction)
        self.toolbar.setIconSize(QSize(35,45))


#======================================================================================================
        
if __name__ == '__main__':

    import sys

    app = QApplication(sys.argv)
    window = MainWindow()
    
    window.resize(550, 740)
    window.show()
    sys.exit(app.exec_())
        
